/*
 * Copyright (c) 2010 Scott Morgan
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package captaintest;

import captaintest.util.Assert;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;

import java.io.File;
import java.io.FileNotFoundException;
import java.text.NumberFormat;
import java.util.List;

public class CaptainTask extends Task {

    public static final String EMMA = "emma";

    private File historyFile;
    private File coverageFile;
    private String coverageFormat = "emma";
    private boolean failOnLowerCoverage = true;
    private String coverageType = null; // any
    private File htmlOutput;

    /**
     * Optional - null will create a history file under the {user.home}/.captain
     * <p/>
     * Location to store the historical best coverage values
     */
    public void setHistoryFile(File historyFile) {
        this.historyFile = historyFile;
    }

    /**
     * Required
     * <p/>
     * Latest test coverage file
     */
    public void setCoverageFile(File coverageFile) {
        this.coverageFile = coverageFile;
    }

    /**
     * Optional - defaults to true
     */
    public void setFailOnLowerCoverage(boolean failOnLowerCoverage) {
        this.failOnLowerCoverage = failOnLowerCoverage;
    }

    /**
     * Optional - null compares all types
     * <p/>
     * Coverage type to compare.  For emma possible values are method, line, block.
     */
    public void setCoverageType(String coverageType) {
        this.coverageType = coverageType;
    }

    /**
     * Optional - if supplied an html report will be generated to this location
     * @param htmlOutput
     */
    public void setHtmlOutput(File htmlOutput) {
        this.htmlOutput = htmlOutput;
    }

    @Override
    public void execute() throws BuildException {
        Assert.notNull(coverageFile, "coverageFile is null");
        Assert.notNull(coverageFormat, "coverageFormat is null");

        createHistoryDirIfNeeded();

        Captain cap = new Captain(historyFile, coverageFile, coverageFormat);
        List<FileCoverage> listFileCoverages = cap.run();

        NumberFormat percentFormat = NumberFormat.getPercentInstance();
        percentFormat.setMinimumFractionDigits(2);

        int errorCount = 0;
        for (FileCoverage fileCoverage : listFileCoverages) {
            log("Checking file: " + fileCoverage.getFileName(), Project.MSG_VERBOSE);
            for (Coverage coverage : fileCoverage.getCoverageList()) {
                if (coverageType == null || coverageType.equals(coverage.getType())) {
                    if (coverage.hasError()) {
                        errorCount++;
                        System.out.println(fileCoverage.getFileName() + " " + coverage.getType() +
                                " old: " + percentFormat.format(coverage.getBestPercentCovered()) +
                                " new: " + percentFormat.format(coverage.getLastPercentCovered()));
                    }
                } else {
                    log("Skipping type: " + coverage.getType(), Project.MSG_VERBOSE);
                }
            }
        }
        if (htmlOutput != null){
            saveHtmlReport(listFileCoverages);
        }

        if (failOnLowerCoverage && (errorCount > 0)) {
            throw new BuildException("Test coverage was reduced for " + errorCount + " files");
        }
    }

    private void saveHtmlReport(List<FileCoverage> fileCoverages) {
        try {
            HtmlReportGenerator generator = new HtmlReportGenerator(fileCoverages, coverageType, htmlOutput);
            generator.generate();
        } catch (FileNotFoundException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }


        //To change body of created methods use File | Settings | File Templates.
    }

    private void createHistoryDirIfNeeded() {
        if (historyFile == null) {
            findHistoryFileLocation();
        }

        File parent = new File(historyFile.getParent());
        if (!parent.exists()) {
            parent.mkdirs();
        }
    }

    private void findHistoryFileLocation() {
        String fileSep = System.getProperty("file.separator");
        String userDir = fileSep;
        Project p = getProject();
        if (p != null) {
            File here = new File(".");
            File baseDir = p.getBaseDir();
            File nextBaseDir = p.getBaseDir();
            while (nextBaseDir != null){
                baseDir = nextBaseDir;
                nextBaseDir = baseDir.getParentFile();
                log("baseDir = " + baseDir, Project.MSG_VERBOSE);
            }
            userDir = here.getAbsolutePath().replace(baseDir.getAbsolutePath(), "");
            userDir = new File(userDir).getParent();
            log("userDir = " + userDir, Project.MSG_VERBOSE);
        } else {
            log("project is null", Project.MSG_WARN);
        }
        String userHome = System.getProperty("user.home");
        String historyFileName = userHome + fileSep + ".captain" + fileSep + userDir + fileSep + "captain.xml";
        log("Using historyFile: " + historyFileName, Project.MSG_VERBOSE);
        historyFile = new File(historyFileName);
    }
}
